package com.imut.hcdp.service.impl;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.math.MathUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import com.imut.hcdp.common.ImutContant;
import com.imut.hcdp.common.RedisCache;
import com.imut.hcdp.common.Rst;
import com.imut.hcdp.config.exception.ServiceException;
import com.imut.hcdp.domain.*;
import com.imut.hcdp.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.imut.hcdp.service.IHcdpOrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;


@Service
@Slf4j
public class HcdpOrderServiceImpl implements IHcdpOrderService
{
    @Autowired
    private HcdpOrderMapper hcdpOrderMapper;

    @Autowired
    private HcdpSeatTypePriceMapper hcdpSeatTypePriceMapper;

    @Autowired
    private HcdpTrainSeatMapper hcdpTrainSeatMapper;

    @Autowired
    private HcdpPassengerMapper hcdpPassengerMapper;

    @Autowired
    private HcdpTrainRouteMapper hcdpTrainRouteMapper;

    @Autowired
    private RedisCache redisCache;

    @Override
    public HcdpOrder selectHcdpOrderById(Long id)
    {
        return hcdpOrderMapper.selectHcdpOrderById(id);
    }


    @Override
    public List<HcdpOrder> selectHcdpOrderList(HcdpOrder hcdpOrder)
    {
        List<HcdpOrder> hcdpOrders = hcdpOrderMapper.selectHcdpOrderList(hcdpOrder);
        for (int i = 0; i < hcdpOrders.size(); i++) {
            HcdpOrder temp = hcdpOrders.get(i);
            List<HcdpPassenger> hcdpPassengers = hcdpPassengerMapper.selectHcdpPassengerList(new HcdpPassenger().setOrderId(temp.getId()));
            temp.setPassengerList(hcdpPassengers);
            Long routeId = temp.getRouteId();
            HcdpTrainRoute hcdpTrainRoute = hcdpTrainRouteMapper.selectHcdpTrainRouteById(routeId);
            temp.setHcdpTrainRoute(hcdpTrainRoute);
        }
        return hcdpOrders;
    }


    @Override
    public int insertHcdpOrder(HcdpOrder hcdpOrder)
    {
        return hcdpOrderMapper.insertHcdpOrder(hcdpOrder);
    }


    @Override
    public int updateHcdpOrder(HcdpOrder hcdpOrder)
    {
        return hcdpOrderMapper.updateHcdpOrder(hcdpOrder);
    }


    @Override
    public int deleteHcdpOrderByIds(Long[] ids)
    {
        return hcdpOrderMapper.deleteHcdpOrderByIds(ids);
    }


    @Override
    public int deleteHcdpOrderById(Long id)
    {
        hcdpPassengerMapper.deleteHcdpPassengerByOrderId(id);
        return hcdpOrderMapper.deleteHcdpOrderById(id);
    }

    @Override
    @Transactional
    public String order(OrderParam orderParam,String orderType) {
        log.info("=============订单类型：{}===========",orderParam);
        //判断行程冲突
        List<HcdpPassenger> personList = orderParam.getPersonList();
        if(CollectionUtils.isEmpty(personList)){
            throw new ServiceException("请添加乘车人信息！");
        }
        Map<String, List<HcdpPassenger>> collect = personList.stream().collect(Collectors.groupingBy(HcdpPassenger::getPhone));
        if(collect.size() != personList.size()){
            throw new ServiceException("乘车人手机号号重复！");
        }

        Map<String, List<HcdpPassenger>> collect1 = personList.stream().collect(Collectors.groupingBy(HcdpPassenger::getCard));
        if(collect1.size() != personList.size()){
            throw new ServiceException("乘车人身份证号重复！");
        }
        //不能再次买同一车程
        for (int i = 0; i < personList.size(); i++) {
            HcdpPassenger hcdpPassenger = personList.get(i);
            String card = hcdpPassenger.getCard();
            //通过身份证查重
            int count = hcdpOrderMapper.checkDistinctOrder(card,orderParam.getRouteId());
            if(count != 0){
                throw new ServiceException("乘车人:【" + card + "】存在行程冲突！");
            }
        }
        //验证余票是否充足
        HcdpTrainSeat hcdpTrainSeat = hcdpTrainSeatMapper.selectHcdpTrainSeatById(orderParam.getSeatId());
        //总票数
        Long seatnum = hcdpTrainSeat.getSeatnum();
        //已出售
        Integer sellTicket = 0;
        //待支付，已支付都算做已出售
        List<HcdpPassenger> sellPerson = hcdpPassengerMapper.
                selectHcdpPassengerListByRouteId(orderParam.getRouteId(),hcdpTrainSeat.getId());
        if(!CollectionUtils.isEmpty(sellPerson)){
            sellTicket = sellPerson.size();
        }
        //可购买票数
        if(seatnum - sellTicket < personList.size() ){
            throw new ServiceException("余票不足!");
        }
        //所有票位
        List<Integer> allTicketList = balanceTicketList(hcdpTrainSeat.getStartno(), hcdpTrainSeat.getEndno());
        log.info("所有票位{}",allTicketList);
        //已售票位
        List<Integer> sellTicketList = sellPerson.stream().map(temp -> temp.getSeatnum()).collect(Collectors.toList());
        log.info("已售票位{}",sellTicketList);
        //可售票
        allTicketList.removeAll(sellTicketList);
        log.info("可售票位{}",allTicketList);

        //入订单表
        HcdpOrder hcdpOrder = new HcdpOrder();
        hcdpOrder.setOutTradeNo(UUID.randomUUID().toString());
        hcdpOrder.setRouteId(orderParam.getRouteId());
        hcdpOrder.setRouteDetailId(orderParam.getRouteDetailId());
        hcdpOrder.setBuyer(orderParam.getBuyer());
        hcdpOrder.setRouteDetailId(orderParam.getRouteDetailId());
        hcdpOrder.setCrttime(new Date());
        hcdpOrder.setStatus(1L); //待支付
        Double totalPrice = 0.0;
        for (int i = 0; i < orderParam.getPersonList().size(); i++) {
            HcdpPassenger hcdpPassenger = orderParam.getPersonList().get(i);
            totalPrice += hcdpPassenger.getSeatprice();
        }
        hcdpOrder.setPrice(new BigDecimal(totalPrice));
        if(orderParam.getChupiao() != null){
            hcdpOrder.setChupiao(orderParam.getChupiao());
        }
        int i = hcdpOrderMapper.insertHcdpOrder(hcdpOrder);
        log.info("新建订单是否成功：{}",i == 1?"是":"否");
        log.info("新建订单信息：{}",hcdpOrder);
        //入乘车人表
        List<HcdpPassenger> personList1 = orderParam.getPersonList();
        for (int i1 = 0; i1 < personList1.size(); i1++) {
            HcdpPassenger temp = personList1.get(i1);
            HcdpPassenger hcdpPassenger = new HcdpPassenger();
            hcdpPassenger.setCrttime(new Date());
            hcdpPassenger.setRouteId(orderParam.getRouteId());
            hcdpPassenger.setRouteDetailId(orderParam.getRouteDetailId());
            hcdpPassenger.setUsername(temp.getUsername());
            hcdpPassenger.setPhone(temp.getPhone());
            hcdpPassenger.setCard(temp.getCard());
            hcdpPassenger.setOrderId(hcdpOrder.getId());
            hcdpPassenger.setBuyerid(orderParam.getBuyer());
            hcdpPassenger.setSeattype(orderParam.getSeatId());
            hcdpPassenger.setSeatnum(allTicketList.get(i1));
            hcdpPassenger.setSeatprice(temp.getSeatprice());
            hcdpPassengerMapper.insertHcdpPassenger(hcdpPassenger);
            log.info("新增乘车人【{}】",temp.getCard());
        }
        return hcdpOrder.getOutTradeNo();
    }

    @Override
    public String refund(Long orderId) {
        HcdpOrder hcdpOrder = hcdpOrderMapper.selectHcdpOrderById(orderId);
        if(hcdpOrder == null){
            return "订单不存在";
        }
        Long status = hcdpOrder.getStatus();
        if(!status.equals(2L)){
            return "当前订单不是【已支付状态】";
        }

        //判断退多少钱
        Long routeId = hcdpOrder.getRouteId();
        HcdpTrainRoute hcdpTrainRoute = hcdpTrainRouteMapper.selectHcdpTrainRouteById(routeId);
        Long sTime = hcdpTrainRoute.getSTime().getTime();
        //已发车 退20%
        if(System.currentTimeMillis() >= sTime){
            log.info("行程已发车，仅退款20%");
            hcdpOrder.setTui(hcdpOrder.getPrice().multiply(new BigDecimal("0.2")));
        }
        //未发车
        if(System.currentTimeMillis() < sTime){
            Long result = sTime - System.currentTimeMillis();
            //大于七天 全退
            if(result >= 1000 * 60 * 60 * 24 * 7){
                log.info("行程未发车且【离发车大于7天】，退款100%");
                hcdpOrder.setTui(hcdpOrder.getPrice());
            }
            // 小于七天大于两天 退60%
            if(result < 1000 * 60 * 60 * 24 * 7 && result >= 1000 * 60 * 60 * 24 * 2){
                log.info("行程未发车且【离发车小于七天大于两天】，退款60%");
                hcdpOrder.setTui(hcdpOrder.getPrice().multiply(new BigDecimal("0.6")));
            }
            //小于两天 退50%
            if(result < 1000 * 60 * 60 * 24 * 2){
                log.info("行程未发车且【离发车小于两天】，退款50%");
                hcdpOrder.setTui(hcdpOrder.getPrice().multiply(new BigDecimal("0.5")));
            }
        }
        //修改为已退款
        hcdpOrder.setStatus(6L);
        int i = hcdpOrderMapper.updateHcdpOrder(hcdpOrder);
        log.info("订单{}，是否退款成功：{}",hcdpOrder.getId(),i == 1?"是":"否");
        if( i != 1){
            return "退款失败";
        }
        return "退款成功！已返回原账户！订单金额：" + hcdpOrder.getPrice().doubleValue() + "退款金额：" + hcdpOrder.getTui().doubleValue();
    }

    @Override
    public String cancelOrder(Long orderId) {
        HcdpOrder hcdpOrder = hcdpOrderMapper.selectHcdpOrderById(orderId);
        if(hcdpOrder == null){
            return "订单不存在";
        }
        Long status = hcdpOrder.getStatus();
        if(!status.equals(1L)){
            return "当前订单不是【待支付状态】";
        }
        //已取消
        hcdpOrder.setStatus(4L);
        int i = hcdpOrderMapper.updateHcdpOrder(hcdpOrder);
        log.info("订单{}，是否取消成功：{}",hcdpOrder.getId(),i == 1?"是":"否");
        if( i != 1){
            return "取消失败";
        }
        return "取消成功";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Rst changeVisa(OrderParam orderParam) {
        //判断改签次数
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(new Date());
        String cacheObject = redisCache.getCacheObject(ImutContant.GAIQIAN + dateStr + ":" + orderParam.getUserCard());
        if(StringUtils.isNotEmpty(cacheObject)){
            return Rst.error("您今日改签次数用完!");
        }
        //改签后的车程应该比当前订单的发车时间晚
        //行程必须是一样的
        //todo
        Long orderId = orderParam.getOrderId();
        //重新下单
        String outTradeNo = order(orderParam,"改签");
        //原订单价格
        Double price = hcdpPassengerMapper.selectRoutePrice(null,orderId,null);
        Double newPrice = hcdpPassengerMapper.selectRoutePrice(null,null,outTradeNo);
        Double e = newPrice - price;
        redisCache.setCacheObject(ImutContant.GAIQIAN + dateStr + ":" + orderParam.getUserCard(),"SB");
        //将原订单改为【改签】
        int i = hcdpOrderMapper.updateHcdpOrder(new HcdpOrder().setId(orderId).setStatus(5L));
        log.info("订单：{} 是否改签成功：{}",orderId,i == 1?"是":"否");
        //新增订单默认为未支付，如果不许要补差额则修改新订单为【已支付】
        if(e > 0){
            //支付宝请求参数
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("chae",Math.abs(e));
            jsonObject.put("outTradeNo",outTradeNo);
            jsonObject.put("subject","改签补差额");
            return Rst.success("改签成功！您需要补充差额：" + Math.abs(e) + "/RMB",jsonObject);
        }else if(e < 0){
            hcdpOrderMapper.updateHcdpByLs(new HcdpOrder().setOutTradeNo(outTradeNo).setStatus(2L));
            return Rst.error("改签成功!差额已退回原账户，金额：" + Math.abs(e) + "/RMB");
        }else{
            return Rst.error("改签成功! 无需退补差额！");
        }
    }

    /**
     * 余票列表
     * @return
     */
    private List<Integer> balanceTicketList(Integer startno,Integer endno){
        ArrayList<Integer> integers = new ArrayList<>();
        if(endno < startno){
            throw new ServiceException("hcdp_train_seat表座位编号异常！");
        }
        for (int i = startno; i <= endno; i++){
            integers.add(i);
        }
        return integers;
    }
}
